#include "Animate.h"
#include <stdio.h>
#include "Common.h"
#include "Logic/Role.h"
#include "Logic/State/StateMachine.h"
#include "Logic/State/State.h"
#include <math.h>

RenderData::RenderData()
{
	point.x = 0;
	point.y = 0;
	state   = 0;
	direction = 0; //down
	time = 25 * 10;     //default OneActTime, no influence anyway.
}

void Animate::Update(const int deltaTime)
{
	m_elapsedTime += deltaTime;
	//int m_perFrameTime = m_speed * 25;
	if (m_elapsedTime >= m_perFrameTime)
	{
		int numFramesToAdvance = (m_elapsedTime / m_perFrameTime);
		m_elapsedTime -= (numFramesToAdvance * m_perFrameTime);

		int desiredFrame = m_curFrame + numFramesToAdvance;
		m_curFrame = desiredFrame % m_numFrame;
	}
	
	m_numSpriteInCurFrame = m_pAct->GetNumSprites(m_curAction,m_curFrame);

}

void Animate::Draw(const int deltaTime)
{
	Update(deltaTime);
	LPDIRECTDRAWSURFACE back_temp = g_pDraw->GetBackSurface();

	for (int i = 0; i < m_numSpriteInCurFrame; i++)
	{
		ROBlt(back_temp,i);
	}

}

int Animate::InitDXSurface()
{
	for (int i = 0; i < m_pSpr->GetNumImage(); i++)
	{
		m_pSprSurfArry[i] = g_pDraw->CreateSurfaceWithSprData(m_pSpr->imgs[i].dat,m_pSpr->imgs[i].w, m_pSpr->imgs[i].h, RGB(0,0,0));
	}

	return 1;
}

CACT* Animate::GetAct()
{
	return m_pAct;
}

Animate::Animate(const char* fileName, Animate* pRefAnimate, bool bIsEntity)
{
	m_curFrame = 0;
	m_direction = 0;
	m_speed = 5;
	m_elapsedTime = 0;
	m_pRefAnimate = pRefAnimate;
	m_curActionId = 1;
	m_bIsEntity = bIsEntity;
	Initialized(fileName);
}

int Animate::Initialized(const char* fileName)
{
	if (!LoadFile(fileName))
		return 0;
	m_pSprSurfArry = new LPDIRECTDRAWSURFACE[m_pSpr->GetNumImage()];
	
	if (!InitDXSurface())
		return 0;

	return 1;
}

int Animate::LoadFile(const char* fileName)
{
	if (strlen(fileName) > 250)
	{
		ShowError("Animate load error! %s name is too long!", fileName);
		return 0;
	}

	char sprFileName[260];
	char actFileName[260];
	sprintf(sprFileName,"%s.spr",fileName);
	sprintf(actFileName,"%s.act",fileName);
	FILE *fp;
	int flen;
	BYTE *sdat;
	if ((fp = fopen(sprFileName, "rb")) == NULL)
	{
		assert(0);
		return 0;
	}
	fseek(fp, 0, SEEK_END);
	flen = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	sdat = (BYTE *)malloc(flen);
	fread(sdat, 1, flen, fp);
	fclose(fp);
	m_pSpr = new CSPR(sdat, flen);
	free(sdat);

	if ((fp = fopen(actFileName, "rb")) == NULL)
	{
		assert(0);
		return 0;
	}
	fseek(fp, 0, SEEK_END);
	flen = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	sdat = (BYTE *)malloc(flen);
	fread(sdat, 1, flen, fp);
	fclose(fp);

	m_pAct = new CACT(sdat);
	free(sdat);

	return 1;
}

HRESULT Animate::ROBlt(LPDIRECTDRAWSURFACE destSurf,int sprId)
{
	int   rotation = m_pAct->GetRotValue(m_curAction,m_curFrame,sprId);
	float scaleX   = m_pAct->GetXMagValue(m_curAction,m_curFrame,sprId);
	float scaleY   = m_pAct->GetYMagValue(m_curAction,m_curFrame,sprId);
	int   mirror   = m_pAct->GetMirrorValue(m_curAction,m_curFrame,sprId);
	int   color    = m_pAct->GetABGRValue(m_curAction,m_curFrame,sprId);
	int sprIndex;
	m_pAct->GetSprNoValue(m_curAction,m_curFrame,sprId,&sprIndex);
	//.act files may include some invalid sprs, don't know why.
	if (sprIndex < 0)
		return 0;
	int width  = m_pSpr->imgs[sprIndex].w;
	int height = m_pSpr->imgs[sprIndex].h;
	int x, y;
	int Xoff,Yoff;
	m_pAct->GetOffsPoint(&Xoff,&Yoff,m_curAction,m_curFrame,sprId);
	if (m_pRefAnimate)
	{
		int extraX,extraY,extraXRef,extraYRef;
		m_pAct->GetExtOffsPoint(&extraX,&extraY,m_curAction,m_curFrame);
		m_pRefAnimate->GetAct()->GetExtOffsPoint(&extraXRef,&extraYRef,m_curAction,m_curFrame);
		x = extraXRef - extraX + Xoff + m_curPoint.x;
		y = extraYRef - extraY + Yoff + m_curPoint.y;
	}
	else
	{
		x = Xoff + m_curPoint.x;
		y = Yoff + m_curPoint.y;
	}

	unsigned char alpha = color >> 24;
	if (rotation == 0 && scaleX == 1 && scaleY == 1 && mirror == 0 && alpha == 0xFF)
	{
		RECT rc;
		rc.left =   x - (width  >> 1);
		rc.top  =   y - (height >> 1);
		rc.bottom = y + (height >> 1);
		rc.right =  x + (width  >> 1);
		return destSurf->Blt(&rc, m_pSprSurfArry[sprIndex], NULL, DDBLT_WAIT | DDBLT_KEYSRC, 0);
	}

	LPDIRECTDRAWSURFACE tempSurf;

	int newW,newH;
	newW = scaleX == 0 ? width : int(scaleX*(float)width);
	newH = scaleY == 0 ? height : int(scaleY*(float)height);
	tempSurf = g_pDraw->CreateSurface(newW,newH,DDSCAPS_SYSTEMMEMORY,RGB(0,0,0));
	
	tempSurf->Blt(NULL,m_pSprSurfArry[sprIndex],NULL,DDBLT_WAIT | DDBLT_KEYSRC,0);



	if (rotation)
	{
		LPDIRECTDRAWSURFACE old = tempSurf;
		tempSurf = g_pDraw->RotateSurf(old,rotation,RGB(0,0,0));
		DDSURFACEDESC desc;
		memset(&desc,0,sizeof(DDSURFACEDESC));
		desc.dwSize = sizeof( DDSURFACEDESC );
		desc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
		tempSurf->GetSurfaceDesc(&desc);
		newW = desc.dwWidth;
		newH = desc.dwHeight;
		SAFE_RELEASE(old);
	}


	if (mirror)
	{
		g_pDraw->MirrorSurf(tempSurf);
	}

	if (alpha != 0xFF)
	{
		POINT dest;
		dest.x = x - (newW >> 1);
		dest.y = y - (newH >> 1);
		HRESULT hr = g_pDraw->AlphaBlt(destSurf, tempSurf, alpha, &dest,NULL,true);
		SAFE_RELEASE(tempSurf);
		return hr;
	}
	else
	{
		RECT rc;
		rc.left =   x - (newW >> 1);
		rc.top  =   y - (newH >> 1);
		rc.bottom = y + (newH >> 1);
		rc.right =  x + (newW >> 1);
		HRESULT hr = destSurf->Blt(&rc, tempSurf, NULL, DDBLT_WAIT | DDBLT_KEYSRC, 0);
		SAFE_RELEASE(tempSurf);
		return hr;
	}
}

